在 Fluentd Bit 中可以使用 read 或 socket 方式處理日誌
在 docker-compose 中當有服務要轉發 Log 到 EFK 平台我們可以如下配置,24224 port 就是與 Fluentd Bit 溝通的點。
logging:
driver: fluentd
options:
fluentd-address: 192.168.101.129:24224
tag: web-backend
在過程中發現先前已開發完的應用程式,要如何區分開發環境,以利於分析時做區分使用以下打 labels
方式。抑或著在在開發的應用程式上進行打標籤的動作來識別,以 spring boot 來說可以在 logback 中定義。
logging:
driver: fluentd
options:
fluentd-address: "192.168.101.129:3003"
labels: "production_status"
labels:
production_status: "dev"
目前在調研的時候有發現配置檔名稱需要是 fluent-bit.conf,否則會出現無法讀取到檔案的問題,但這問題也不確定是不是我的問題XD
每個傳入數據(Log、Metric)都視為一個事件(Event)或記錄(Record)
Mar 8 10:03:36 ubuntu dockerd[18162]: time="2021-03-08T10:03:36.491688014+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:zkgfqq2qthpzdtgrk2w3clhqo leaving:false netPeers:1 entries:2 Queue qLen:0 netMsg/s:0"
Mar 8 10:03:36 ubuntu dockerd[18162]: time="2021-03-08T10:03:36.493309528+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:6r7udn06llggcz5awzjfm992m leaving:false netPeers:1 entries:3 Queue qLen:0 netMsg/s:0"
Mar 8 10:07:43 ubuntu systemd[1]: Started Session 124 of user xxxx.
Mar 8 10:08:36 ubuntu dockerd[18162]: time="2021-03-08T10:08:36.691648447+08:00" level=info msg="NetworkDB stats ubuntu(857ee003b9b7) - netID:zkgfqq2qthpzdtgrk2w3clhqo leaving:false netPeers:1 entries:2 Queue qLen:0 netMsg/s:0"
上面提供的日誌共有 4 個獨立事件,而每個事件由一些特定的組件組合,像是 TIMESTAMP、MESSAGE 等。
對事件進行修改或刪除都視為過濾(Filtering)。
範例
被轉發至 Fluent Bit 的每個事件都被分配一個標籤(Tag)。標籤是一個內部字串,路由器在之後階段用它確定它必須經過哪個 Filter
或 Output
階段。
input 為 Forward 是不分配標籤。標記必須始終匹配規則,這與路由會有關連。
用於表示創建事件的時間,每個事件都會包含。
Fluentd bit 允許將收集和處理的事件透過路由傳遞到一個或多個目的地,這是使用匹配(Match)來完成。
匹配是一個簡單的規則,用於選擇與標籤(Tag)匹配已定義規則的事件。
來源端數據可以是結構或是非結構化。結構化可以有 Key:Value 格式,並在做過濾時可更加方便。
Fluent Bit 處理數據時,使用系統記憶體堆作為主要和臨時的位置來儲存事件,接著再將它們發送到私有儲存區中,以處理事件。可以這麼的理解用於將處理後的數據放置到臨時位置,直到準備好發送為止
在記憶體中緩衝是一個最快的機制,緩衝(Buffering)是一個儲存事件的位置,在處理和提交事件時,仍然能夠儲存事件。
當獲取第三方服務事件時,該服務的網路故障或延遲非常普遍時,當接收到要處理的新數據時無法夠快交付數據時,將可能會面臨backpressure
,使得記憶體大量被消耗。而 Mem_Buf_Limit
能夠抑制獲取的事件數據量,進而避免。
整體資料流程如下圖所示
每個步驟都有相關的套件可使用
範例
[INPUT]
Name cpu
Tag my_cpu
[INPUT]
Name mem
Tag my_mem
[OUTPUT]
Name es
Match my_cpu
[OUTPUT]
Name stdout
Match my_mem # 為了將數據輸出至目的,因此必須做匹配動作
當 Input 插件發出事件時,會將事件分組成一個塊(Chunk),通常是 2Mb,預設下塊都在記憶體中創建。
記憶體是一個很快的機制,對系統附載也小。但當網路發生問題或是有延遲,導致服務無法以正常速率進行傳送事件,此使記憶體的消耗將大幅增加並不斷累積數據,使得數據超出了傳遞的大小。這將有機會觸發 OOM,因此可使用 mem_buf_limit
方式進行限制,當超過 mem_buf_limit
限制則 Input 會暫停運作,同時間遺失數據的可能性將增加。
使用 Filesystem 緩衝有助於 backpressure 和記憶體控制。
為 Input 進行記憶體和檔案系統緩衝的配置將會有性能和數據安全的優勢。使用 Filesystem 時系統會將塊(Chunk)映射至硬碟上形成一個副本,同時會控制塊的量以處裡記憶體高使用率和 backpressure 產生的作用。
storage.max_chunks_up
預設為在記憶體儲存 128 個塊。在能夠使用塊下能夠進行交付或接收數據,剩下的塊是非啟用狀態這些將會用在檔案系統中,除非可進行交付,否則不再記憶體中使用。
當 Input 啟用 mem_buf_limit
和 storage.type
作為檔案系統,當 mem_buf_limit
達到閾值時,不是暫停 Input,而是所有新數據將轉到檔案系統中已關閉的塊(Chunk)。這控制了記憶體也保證數據不遺失。
塊(Chunk)也許會透過 Tag 將其路由至目的地。而目的地可以有很多個目標,而每個傳送到目標的速率將會不一樣,而這不一樣將會使其中一個目標產生 backpressure
。可透過 storage.total_limit_size
進行限制,該限制當被觸發時,輸出到目的地的隊列中最舊的塊(Chunk)將被丟棄。
相關的儲存配置可參考此鏈接
架構如下圖,我們可以這樣設計
藍色為一台主機,而紅色是不同開發環境的主機,fluent
充當 agent,在每台主機蒐集 log 並將其傳送至 Elasticsearch 上,後須搭配 Praeco
實現 log 告警。
在 fluent-bit
配置如下,Filter 可以想成是 pipeline 概念。
[SERVICE]
flush 1
log_Level info
daemon off
parsers_File parsers.conf
# use driver method
[INPUT]
name forward
listen 0.0.0.0
port 24224
tag docker.socket
# use read
[INPUT]
name tail
tag docker.file
path /fluentd/log/containers/web.log
DB /var/log/flb_docker.db
mem_buf_limit 5MB
skip_long_lines Off
refresh_interval 10
Docker_Mode On
Docker_Mode_Flush 4
Docker_Mode_Parser multiline2 # 捕獲 JAVA Exception Stack
[FILTER]
Name parser
Match docker.socket
Key_Name log
Parser spring # 解析 JAVA log
Reserve_Data On
Preserve_Key On
[FILTER]
Name parser
Match docker.file
Key_Name log
Parser docker # 處裡 Json
Reserve_Data On
Preserve_Key On
[FILTER]
Name parser
Match docker.file
Key_Name log
Parser h365
Reserve_Data On # 將原始直對保留在解析的結果中
Preserve_Key On # 將原始的 Key_Name 字段保留在解析的結果中
# 新增 Tag
[FILTER]
Name record_modifier
Match docker.file
Record production_status dev
Record container_name web
Remove_key time
[OUTPUT]
name es
match *
host 192.168.101.129
port 3001
index fluent-bit
logstash_format on
logstash_Prefix 120.log
logstash_dateformat %Y%m%d
replace_dots on
retry_limit false
parser,這部分其實滿重要,如果 Log 沒制訂統一規範時,解析會變得很麻煩。解析部分就得研究正規表示XD
[PARSER]
Name spring
Format regex
Regex /^(?<time>((\d)+((-|:)\d+)+(\W+)\S+)+)(\s)?(?<level>\S+)\W+(?<logger>\S+)\W+(?<message>(\S|\s)*)/
Time_Key time
Time_Format %b %d %H:%M:%S
[PARSER]
Name multiline2
Format regex
Regex /(?<log>^{"log":"((\d)+((-|:)\d+)+.*))/
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
[PARSER]
Name h365
Format regex
Regex /^(?<time>((\d)+((-|:)\d+)+))(\S)+(\s)+(?<thread>(\S)+)(\W)+(?<level>\S+)(\W+)(?<message>(\S|\s)*)/
Time_Key time
Time_Format %b %d %H:%M:%S
當然可以用 --log-driver
轉發
docker run -it -d -p 80:80 --log-driver fluentd --log-opt fluentd-address=tcp://192.168.101.129:24224 --log-opt labels=production_statu
s=testing --log-opt tag=web nginx
使用 docker-compose logging 設定進行日誌轉發,此方式本地不會儲存 Log,配置如下
logging:
driver: fluentd
options:
fluentd-address: "192.168.101.120:24224"
tag: "spring boot"
labels: "production_status"
labels:
production_status: "dev"
會存在無法分辨是哪個容器產生,因此使用 labels
關鍵字實現自訂義標籤。這樣可用來解決分辨問題源,可參考此鏈接。